﻿using System;
using System.Runtime.Serialization;
using System.Xml.Linq;

namespace NCMIS.ObjectModel.MetaData
{
    /// <summary>
    /// Represents property definitions for an object-type.
    /// </summary>
    [KnownType(typeof(PropertyBooleanDefinition))]
    [KnownType(typeof(PropertyDateTimeDefinition))]
    [KnownType(typeof(PropertyDecimalDefinition))]
    [KnownType(typeof(PropertyHtmlDefinition))]
    [KnownType(typeof(PropertyIdDefinition))]
    [KnownType(typeof(PropertyIntegerDefinition))]
    [KnownType(typeof(PropertyStringDefinition))]
    [KnownType(typeof(PropertyUriDefinition))]
    [DataContract(Name = "propertyDefinition", Namespace = CmisNs.Cmis)]
    public abstract class PropertyDefinition
    {
        /// <summary>
        /// Unique identifier for a property in the repository. If two object-types each contain property
        /// definitions with the same ID, those property definitions are the same.
        /// </summary>
        [DataMember(Name = "id")]
        public string Id
        {
            get;
            set;
        }

        /// <summary>
        /// The underlying repository's name for the property.
        /// </summary>
        [DataMember(Name = "localName")]
        public string LocalName
        {
            get;
            set;
        }

        /// <summary>
        /// The internal namespace for the underlying repository's name for the property.
        /// </summary>
        [DataMember(Name = "localNamespace")]
        public string LocalNamespace
        {
            get;
            set;
        }

        /// <summary>
        /// A display name for presentation by application.
        /// </summary>
        [DataMember(Name = "displayName")]
        public string DisplayName
        {
            get;
            set;
        }

        /// <summary>
        /// A query name for query operations on properties.
        /// </summary>
        [DataMember(Name = "queryName")]
        public string QueryName
        {
            get;
            set;
        }

        /// <summary>
        /// An optional description of the property.
        /// </summary>
        [DataMember(Name = "description")]
        public string Description
        {
            get;
            set;
        }

        /// <summary>
        /// Indicates the type of the property.
        /// </summary>
        [DataMember(Name = "propertyType")]
        public CmisPropertyType PropertyType
        {
            get;
            set;
        }

        /// <summary>
        /// Indicates whtether the property can have "zero or one" or "zero or more" values.
        /// </summary>
        [DataMember(Name = "cardinality")]
        public Cardinality Cardinality
        {
            get;
            set;
        }

        /// <summary>
        /// Indicates under what circumstances the value of a property may be updated.
        /// </summary>
        [DataMember(Name = "updatability")]
        public Updatability Updatability
        {
            get;
            set;
        }

        /// <summary>
        /// Indicates whether the property definition is inherited from the parent-type, when true, or it
        /// is explicitly defined for this object-type, when false.
        /// </summary>
        [DataMember(Name = "inherited")]
        public bool Inherited
        {
            get;
            set;
        }

        /// <summary>
        ///  If true, then the value of this property must never be set to the "not set" state when an object
        ///  of this type is created/updated. If not provided during a create or update operation, the
        ///  repository must provide a value for this property. If a value is not provided, then the default
        ///  value defined for the property must be set. If no default value is provided and no default value
        ///  is defined, the repository must throw an exception.
        ///  A property definition should never state that a property has a "required" value of true and an
        ///  updatability value of "readonly".
        /// </summary>
        [DataMember(Name = "required")]
        public bool Required
        {
            get;
            set;
        }

        /// <summary>
        /// Indicates whether or not the property may appear in the WHERE clause of a CMIS query statement.
        /// This attribute must have a value of false if the Object-type’s attribute for "Queryable" is set
        /// to false.
        /// </summary>
        [DataMember(Name = "queryable")]
        public bool Queryable
        {
            get;
            set;
        }

        /// <summary>
        /// Indicates whether the property can appear in the ORDER BY clause of a CMIS query statement or an
        /// ORDERBY parameter. This property must be false for any property whose cardinality is "multi".
        /// </summary>
        [DataMember(Name = "orderable")]
        public bool Orderable
        {
            get;
            set;
        }

        /// <summary>
        /// This attribute is only applicable to properties that provide a value for the "Choices" attribute.
        /// If false, then the data value for the property MUST only be one of the values specified in the
        /// "Choices" attribute. If true, then values other than those included in the "Choices" attribute may
        /// be set for the property.
        /// </summary>
        [DataMember(Name = "openChoice")]
        public bool OpenChoice
        {
            get;
            set;
        }

        public virtual XElement ToXElement()
        {
            return null;
        }
    }
}
